/** @file
  Sample ACPI Platform Driver

  Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
  Copyright (C) 2022 - 2023, Phytium Technology Co., Ltd. All rights reserved.<BR>
  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include <PiDxe.h>

#include <Protocol/AcpiTable.h>
#include <Protocol/FirmwareVolume2.h>

#include <Library/BaseLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/HobLib.h>
#include <Library/BaseMemoryLib.h>
#include <OEMSvc.h>
#include <ArmPlatform.h>
#include <IndustryStandard/Acpi.h>
#include <OemConfigData.h>
#include <Library/PhytiumPowerControlLib.h>
//#include "AdvancedConfigData.h"
#include <CpuConfig.h>
#include <CpuConfigFormGuid.h>
#include <Protocol/AcpiSystemDescriptionTable.h>
#include <Library/AmlLib/AmlLib.h>
#include <IndustryStandard/AcpiAml.h>
#include <IndustryStandard/Acpi.h>
//[gliu-0020]add-start
#include <Guid/TtyTerm.h>
#include <IndustryStandard/SerialPortConsoleRedirectionTable.h>
#include <Protocol/DevicePath.h>
#include <Library/DevicePathLib.h>
#include <Protocol/SerialIo.h>
//#include <Protocol/CrPolicyProtocol.h>
//[gliu-0020]add-end
#include <Library/KlSetupVarRWLib.h>
//[jianghui-0007] add start
#include <Library/PhytiumSpiNorFlashLib.h>
//[jianghui-0007] add end

#define ACPI_DEBUG

#ifdef ACPI_DEBUG
#define DBG(arg...) DEBUG((EFI_D_ERROR,## arg))
#else
#define DBG(arg...)
#endif

#define EFI_ACPI_MAX_NUM_TABLES         20
//[gliu-0020]
//#define DSDT_SIGNATURE                  0x54445344
//[gliu-0020]

// Differs from Juno, we have another affinity level beyond cluster and core
// 0x20000 is only for socket 0
#define PLATFORM_GET_MPID(ClusterId, CoreId)   (((ClusterId) << 8) | (CoreId))
#define PM_EC 1


//[gliu-0020]add-start
STATIC
VOID
AcpiPlatformChecksum (
  IN UINT8      *Buffer,
  IN UINTN      Size
  );

STATIC
VOID
DoUpdateDsdt (
  IN  EFI_ACPI_SDT_HEADER      *Table,
  IN  UINTN                     TableKey
  )
{
  EFI_STATUS                    Status;
  UINTN                         VarSize;
  EFI_ACPI_TABLE_PROTOCOL       *AcpiTable;
  EFI_ACPI_DESCRIPTION_HEADER   ** NewTable;
  AML_ROOT_NODE_HANDLE          RootNodeHandle;
  AML_OBJECT_NODE_HANDLE        NameOpIdNode;
  OEM_CONFIG_DATA               OemConfigData;
  UINTN                         TableSize;
  UINTN                         TableHandle;
  UINT8                         EnableX100Display;
  UINT8                         EnableEc;
  UINT8                         EnableOptee;
  UINT8                         EnableHda;
  UINT8                         EnableESSX8336;
  UINT8                         EnableESSX8388;
  UINT32                        S3Flag;
  SYSTEM_SETUP_CONFIGURATION    *SetupVar;
  //[gliu-0052]add-begin
  UINT8                         EnableGmac;
  //[gliu-0052]add-end

  EnableOptee = 0;
  EnableX100Display = 0;
  EnableGmac = 1;
  SetupVar = NULL;
  Status = KlSetupVarRead(&SetupVar);
  if(!EFI_ERROR(Status))
  {
    EnableX100Display = SetupVar->X100Config.DisplayEnable;
    if (SetupVar->X100Config.X100IsExisted == 0) {
      EnableX100Display = 0;
    }
    DEBUG ((EFI_D_INFO, "X100Config.DisplayEnable : %d\n", SetupVar->X100Config.DisplayEnable));
    if(SetupVar->NetController != 0) {
      EnableGmac = 1;
    }else{
      EnableGmac = 0;
    }
    DEBUG ((EFI_D_INFO, "EnableGmac : %d\n", EnableGmac));
  }

  Status = gRT->GetVariable (
  			      OEM_CONFIG_NAME,
  				  &gOemDataSetupGuid,
  				  NULL,
  				  &VarSize,
  				  &OemConfigData
  				  );

  if (EFI_SUCCESS == Status) {
    DEBUG((EFI_D_INFO, "EnableOptee:%d\n", OemConfigData.EnableOptee));
    EnableOptee = OemConfigData.EnableOptee;
  }
  DEBUG ((EFI_D_INFO, "Update ACPI X100Config.X100IsExisted : %d\n", SetupVar->X100Config.X100IsExisted));
  S3Flag = pm_get_s3_flag_source();
  if (S3Flag == PM_EC) {
    EnableEc = 0x1;
  } else {
    EnableEc = 0;
  }

#ifdef DEMO
  EnableESSX8336 = 0;
  EnableESSX8388 = 0;
  EnableHda = 1;
#elif HWQS
  EnableESSX8336 = 1;
  EnableESSX8388 = 1;
  EnableHda = 1;//[gliu-0041]
#elif DT_D2008_2101
  EnableESSX8336 = 1;
  EnableESSX8388 = 1;
  EnableHda = 1;  
#elif DOMESTIC
  EnableESSX8336 = 0;
  EnableESSX8388 = 1;
  EnableHda = 0;
#elif  NOTEBOOK_V1
  EnableESSX8336 = 1;
  EnableESSX8388 = 0;
  EnableHda = 0;
#elif NOTEBOOK_V2
  EnableESSX8336 = 0;
  EnableESSX8388 = 0;
  EnableHda = 1;
#elif Z706_HTDD208
  EnableESSX8336 = 0;
  EnableESSX8388 = 0;
  EnableHda = 1;
#else 
  EnableESSX8336 = 0;
  EnableESSX8388 = 0;
  EnableHda = 0;  
#endif

  NewTable = (EFI_ACPI_DESCRIPTION_HEADER**)
			  AllocateZeroPool (
				(sizeof (EFI_ACPI_DESCRIPTION_HEADER*))
				);

  if (NewTable == NULL) {
	Status = EFI_OUT_OF_RESOURCES;
	DEBUG ((
	  DEBUG_ERROR,
	  "ERROR: DSDT-FIXUP: Failed to allocate memory for Table ."
	  " Status = %r\n",
	  Status
	  ));
	ASSERT_EFI_ERROR(Status);
  }

    Status = AmlParseDefinitionBlock (
             (CONST EFI_ACPI_DESCRIPTION_HEADER *)Table,
             &RootNodeHandle
             );

    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: DSDT-FIXUP:"
        " Failed to parse DSDT Template. Status = %r\n",
        Status
        ));
	  ASSERT_EFI_ERROR(Status);
    }

	//Update EnableOptee
    Status = AmlFindNode (
               RootNodeHandle,
               "\\_SB_.OPTE",
               &NameOpIdNode
               );
    if (EFI_SUCCESS == Status) {
		if (!EnableOptee) {
            /*AmlNameOpUpdateInteger(NameOpIdNode, EnableOptee);*/
    	  AmlDetachNode(NameOpIdNode);
      	  DEBUG((EFI_D_INFO, "Delete Open Tee Node\n"));
		}
    }

    //Update EnableEc
	if (!EnableEc) {
	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.LPC1",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
        AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete Lpc Note\n"));
      }
	}

  //[gliu-0052]add-begin
  //Update EnableGmac
  if (EnableGmac == 0) {
    Status = AmlFindNode (
                  RootNodeHandle,
                  "\\_SB_.ETH0",
                  &NameOpIdNode
                  );
    if (EFI_SUCCESS == Status) {
      AmlDetachNode(NameOpIdNode);
      DEBUG((EFI_D_INFO, "Delete ETH0 Note\n"));
    }
    Status = AmlFindNode (
                  RootNodeHandle,
                  "\\_SB_.ETH1",
                  &NameOpIdNode
                  );
    if (EFI_SUCCESS == Status) {
      AmlDetachNode(NameOpIdNode);
      DEBUG((EFI_D_INFO, "Delete ETH1 Note\n"));
    }
  }
  //[gliu-0052]add-end
  
	if (!EnableX100Display) {
	  //Update EnableX100Display
      Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.XDIS",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
        AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete XDIS Node\n"));
      }
  } else {
    if (PcdGet32(PcdUnloadXDIS)) {
      Status = AmlFindNode (
                    RootNodeHandle,
                    "\\_SB_.XDIS",
                    &NameOpIdNode
                    );
      if (EFI_SUCCESS == Status) {
        AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete XDIS Node 2\n"));
      }
    }
  }

	if (!EnableHda) {
      //Update EnableHda
      Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.HDA0",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
        AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete HDA0 Node\n"));
      }
	}

  if (SetupVar->X100Config.X100IsExisted == 0) {
	  EnableESSX8336 = 0;
	  EnableESSX8388 = 0;
	}

	if (!EnableESSX8336) {
	  //Update ESSX8336
      Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.Dec0",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete ESSX8336 Node\n"));
      }

	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.Dec1",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete PHYT8005 Node\n"));
      }
	}

    if (!EnableESSX8388) {
	  //Update ESSX8388
      Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.Dec2",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
      AmlDetachNode(NameOpIdNode);
      DEBUG((EFI_D_INFO, "Delete ESSX8388 Node\n"));
    }

	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.Dec3",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete PHYT8004 Node\n"));
      }
	}

  if (!SetupVar->X100Config.X100IsExisted) {
	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.Dec4",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete PHYT8006 Node\n"));
      }
	} else {
	  //Update DpChannel
#if 0
      Status = AmlFindNode (
                  RootNodeHandle,
                  "\\_SB_.Dec4.DPCN",
                  &NameOpIdNode
                  );
      if (EFI_SUCCESS == Status) {
        AmlNameOpUpdateInteger(NameOpIdNode, SetupVar->X100Config.X100IsExisted.DpChannel);
        DEBUG((EFI_D_INFO, "Update Dec4.DPCN\n"));
      }
#endif
  }

    UINT8   BiosMode = 0;

    VarSize = sizeof(BiosMode);
    Status = gRT->GetVariable (
                    VAR_CPU_BIOSMODE_CONFIG_NAME,
                    &gCpuBiosModeVarGuid,
                    NULL,
                    &VarSize,
                    &BiosMode
                    );

    if (BiosMode) {
      //Delete PL011 uart
	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.UAR0",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete UAR0\n"));
      }

	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.UAR1",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete UAR1\n"));
      }

	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.UAR2",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete UAR2\n"));
      }

	  Status = AmlFindNode (
                 RootNodeHandle,
                 "\\_SB_.UAR3",
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
  	    AmlDetachNode(NameOpIdNode);
        DEBUG((EFI_D_INFO, "Delete UAR3\n"));
      }
    }

    // Serialize the tree.
    Status = AmlSerializeDefinitionBlock (
               RootNodeHandle,
               NewTable
               );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: DSDT-FIXUP: Failed to Serialize DSDT Table Data."
        " Status = %r\n",
        Status
        ));
	  ASSERT_EFI_ERROR(Status);
    }

    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
    if (EFI_ERROR (Status)) {
	  ASSERT_EFI_ERROR(Status);
    }

    Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
    if (EFI_ERROR(Status)) {
      DEBUG((EFI_D_ERROR, "ERROR: DSDT-FIXUP: Failed to uninstall Dsdt table.\n"));
	  ASSERT_EFI_ERROR(Status);
    }

    TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) *NewTable)->Length;
    //
    // Install ACPI table
    //
    Status = AcpiTable->InstallAcpiTable (
                          AcpiTable,
                          *NewTable,
                          TableSize,
                          &TableHandle
                          );

    if (EFI_ERROR(Status)) {
      DEBUG((EFI_D_ERROR, "ERROR: DSDT-FIXUP: Failed to install Dsdt table.\n"));
	  ASSERT_EFI_ERROR(Status);
    }

  if (RootNodeHandle != NULL) {
    Status = AmlDeleteTree (RootNodeHandle);
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: DSDT-FIXUP: Failed to cleanup AML tree."
        " Status = %r\n",
        Status
        ));
      ASSERT_EFI_ERROR(Status);
    }
  }
  if(SetupVar != NULL){
    FreePool(SetupVar);
  }
}


STATIC
VOID
UpdateAcpiRamAfterPciEnum (
  IN EFI_EVENT    Event,
  IN VOID         *Context
  )
{
  EFI_STATUS                Status;
  VOID                      *Interface;
  UINTN                     TableKey;
  UINTN                     i;
  EFI_ACPI_SDT_HEADER       *Table;
  EFI_ACPI_SDT_PROTOCOL     *AcpiTableProtocol;
  EFI_ACPI_TABLE_VERSION    TableVersion;
  //EFI_ACPI_TABLE_PROTOCOL            *AcpiTable = NULL;

  Status = gBS->LocateProtocol(&gKunLunAllDriversConnectedProtocolGuid, NULL, (VOID**)&Interface);
  if (EFI_ERROR(Status)) {
    return;
  }
  gBS->CloseEvent(Event);

  // Find the AcpiTable protocol
  Status = gBS->LocateProtocol(&gEfiAcpiSdtProtocolGuid, NULL, (VOID**) &AcpiTableProtocol);
  if (EFI_ERROR(Status)) {
    DEBUG((EFI_D_ERROR, "Unable to locate ACPI table protocol\n"));
    ASSERT_EFI_ERROR(Status);
  }

  // Search for DSDT Table
  for (i = 0; i < EFI_ACPI_MAX_NUM_TABLES; i++) {
    Status = AcpiTableProtocol->GetAcpiTable(i, &Table, &TableVersion, &TableKey);
    if (EFI_ERROR(Status))
      break;
    if (Table->Signature == EFI_ACPI_6_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
      DoUpdateDsdt(Table, TableKey);
      break;
    }
  }
}
//[gliu-0020]add-end
STATIC
VOID
UpdateSsdt (
  IN EFI_ACPI_COMMON_HEADER   *AcpiHdr
  )
{

  EFI_STATUS              Status;
  EFI_STATUS              Status1;
  AML_ROOT_NODE_HANDLE    RootNodeHandle;
  AML_OBJECT_NODE_HANDLE    NameOpIdNode;
  EFI_ACPI_DESCRIPTION_HEADER  ** Table;
  UINTN VarSize;
  UINT8   BiosMode;

  VarSize = sizeof(BiosMode);
  Status = gRT->GetVariable (
                  VAR_CPU_BIOSMODE_CONFIG_NAME,
                  &gCpuBiosModeVarGuid,
                  NULL,
                  &VarSize,
                  &BiosMode
                  );

  DEBUG((EFI_D_INFO, "BiosMode:%d\n", BiosMode));
  if (!BiosMode) {
	return;
  }

  Table = (EFI_ACPI_DESCRIPTION_HEADER**)
			  AllocateZeroPool (
				(sizeof (EFI_ACPI_DESCRIPTION_HEADER*))
				);

  if (Table == NULL) {
	Status = EFI_OUT_OF_RESOURCES;
	DEBUG ((
	  DEBUG_ERROR,
	  "ERROR: SSDT-FIXUP: Failed to allocate memory for Table."
	  " Status = %r\n",
	  Status
	  ));
	  ASSERT_EFI_ERROR(Status);
  }

  //Parse the SSDT Template.
  Status = AmlParseDefinitionBlock (
             (CONST EFI_ACPI_DESCRIPTION_HEADER   *)AcpiHdr,
             &RootNodeHandle
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "ERROR: SSDT-FIXUP:"
      " Failed to parse SSDT Template. Status = %r\n",
      Status
      ));
	ASSERT_EFI_ERROR(Status);
  }

  Status = AmlFindNode (
             RootNodeHandle,
             "\\_SB_.PCI0._PRT",
             &NameOpIdNode
             );
  if (EFI_SUCCESS == Status) {
    AmlDetachNode(NameOpIdNode);
    DEBUG((EFI_D_INFO, "Delete PCI0._PRT\n"));
  }

  // Serialize the tree.
  Status = AmlSerializeDefinitionBlock (
             RootNodeHandle,
			 Table
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "ERROR: SSDT-FIXUP: Failed to Serialize SSDT Table Data."
      " Status = %r\n",
      Status
      ));
  }

  if (RootNodeHandle != NULL) {
    Status1 = AmlDeleteTree (RootNodeHandle);
    if (EFI_ERROR (Status1)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: SSDT-FIXUP: Failed to cleanup AML tree."
        " Status = %r\n",
        Status1
        ));
	    ASSERT_EFI_ERROR(Status);
    }
  }
  CopyMem(AcpiHdr, *Table, (*Table)->Length);
}

STATIC
VOID
RemoveUnusedCoreNode(
	IN OUT EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE *Table,
	IN UINT8	CoreCount
)
{
	UINTN	CurrPtr,NewPtr;
	if(CoreCount >= GIC_INTERFACES_MAX_COUNT)
		return ;
	CurrPtr = (UINTN)&(Table->GicInterfaces[GIC_INTERFACES_MAX_COUNT]);
	NewPtr = (UINTN)&(Table->GicInterfaces[CoreCount]);
	CopyMem((VOID*)NewPtr,(VOID*)CurrPtr,(UINTN)Table + Table->Header.Header.Length - CurrPtr);
	Table->Header.Header.Length -= CurrPtr - NewPtr;
	return ;
}

STATIC
EFI_STATUS
UpdateMadt(
	IN OUT EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE	*Table
)
{
	EFI_HOB_GUID_TYPE		  *GuidHob;
	PHYTIUM_CPU_INFO		  *CpuInfo;
	UINT8		CoreCount = 0;
	UINT8		i;
	DEBUG((EFI_D_INFO,"Status update MADT Table\n"));
	GuidHob = GetFirstGuidHob(&gPlatformCpuInforGuid);
	if (GuidHob == NULL){
		DEBUG((EFI_D_ERROR,"%a(),Get cpu info hob failed!\n",__FUNCTION__));
		return EFI_UNSUPPORTED;
	}
	CpuInfo = (PHYTIUM_CPU_INFO *) GET_GUID_HOB_DATA(GuidHob);
	DEBUG((EFI_D_INFO,"CpuVersion:%lld\nCpuCoreInfor->CpuFreq:%lld,CpuCoreInfor->CpuL3CacheSize:%lld,CpuCoreInfor->CpuL3CacheLineSize:%lld\nCpuMapInfor->CpuMapCount:%lld,CpuMapInfor->CpuMap[0]:%llx\n",
      	CpuInfo->CpuCoreInfo,CpuInfo->CpuCoreInfo.CpuFreq,CpuInfo->CpuCoreInfo.CpuL3CacheSize,CpuInfo->CpuCoreInfo.CpuL3CacheLineSize,
      	CpuInfo->CpuMapInfo.CpuMapCount,CpuInfo->CpuMapInfo.CpuMap[0]));
	for(i=0;i<64;i++){
		if((CpuInfo->CpuMapInfo.CpuMap[0]>>i)&0x0000000000000001){			//core existed
			Table->GicInterfaces[CoreCount].AcpiProcessorUid = (i/CORCOUNT_PER_CLUSTER)*2+i%CORCOUNT_PER_CLUSTER;		//AcpiCpuUid
			Table->GicInterfaces[CoreCount].MPIDR = PLATFORM_GET_MPID(i/CORCOUNT_PER_CLUSTER,i%CORCOUNT_PER_CLUSTER);
			Table->GicInterfaces[CoreCount].GICRBaseAddress = FixedPcdGet64 (PcdGicRedistributorsBase) + 0x040000*(i/CORCOUNT_PER_CLUSTER)+0x020000*(i%CORCOUNT_PER_CLUSTER);
			DEBUG((EFI_D_INFO,"index:%d,AcpiProcessorUid:%d,MPIDR:%x,GICRBaseAddress,%x\n",i,Table->GicInterfaces[CoreCount].AcpiProcessorUid,Table->GicInterfaces[CoreCount].MPIDR,Table->GicInterfaces[CoreCount].GICRBaseAddress));
			CoreCount++;
		}
		if(CoreCount >= GIC_INTERFACES_MAX_COUNT)
			break;
	}
	RemoveUnusedCoreNode(Table,CoreCount);
	return EFI_SUCCESS;
}

STATIC
EFI_STATUS
UpdateDsdt(
	IN OUT EFI_ACPI_COMMON_HEADER *AcpiHdr
)
{
  VOID                            *EventReg;

  EfiCreateProtocolNotifyEvent (
        &gKunLunAllDriversConnectedProtocolGuid,
        TPL_CALLBACK,
        UpdateAcpiRamAfterPciEnum,
        NULL,
        &EventReg
        );

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
UpdateAcpiTable (
  IN OUT EFI_ACPI_COMMON_HEADER      *TableHeader
)
{
	switch (TableHeader->Signature) {
		case EFI_ACPI_6_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
			DEBUG((EFI_D_INFO,"%a(),%d,ssdt.asl update\n",__FUNCTION__,__LINE__));
			UpdateSsdt (TableHeader);
			break;

		case EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
			DEBUG((EFI_D_INFO,"%a(),%d,Madt.asl update\n",__FUNCTION__,__LINE__));
			UpdateMadt((EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE *)TableHeader);
			break;

		case EFI_ACPI_6_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
			DEBUG((EFI_D_INFO,"%a(),%d,Dsdt.asl update\n",__FUNCTION__,__LINE__));
			UpdateDsdt(TableHeader);
			break;

		default:
			break;

	}
	return EFI_SUCCESS;
}



/**
  Locate the first instance of a protocol.  If the protocol requested is an
  FV protocol, then it will return the first FV that contains the ACPI table
  storage file.

  @param  Instance      Return pointer to the first instance of the protocol

  @return EFI_SUCCESS           The function completed successfully.
  @return EFI_NOT_FOUND         The protocol could not be located.
  @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.

**/
EFI_STATUS
LocateFvInstanceWithTables (
  OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
  )
{
  EFI_STATUS                    Status;
  EFI_HANDLE                    *HandleBuffer;
  UINTN                         NumberOfHandles;
  EFI_FV_FILETYPE               FileType;
  UINT32                        FvStatus;
  EFI_FV_FILE_ATTRIBUTES        Attributes;
  UINTN                         Size;
  UINTN                         Index;
  EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;

  FvStatus = 0;

  //
  // Locate protocol.
  //
  Status = gBS->LocateHandleBuffer (
                   ByProtocol,
                   &gEfiFirmwareVolume2ProtocolGuid,
                   NULL,
                   &NumberOfHandles,
                   &HandleBuffer
                   );
  if (EFI_ERROR (Status)) {
    //
    // Defined errors at this time are not found and out of resources.
    //
    return Status;
  }



  //
  // Looking for FV with ACPI storage file
  //

  for (Index = 0; Index < NumberOfHandles; Index++) {
    //
    // Get the protocol on this handle
    // This should not fail because of LocateHandleBuffer
    //
    Status = gBS->HandleProtocol (
                     HandleBuffer[Index],
                     &gEfiFirmwareVolume2ProtocolGuid,
                     (VOID**) &FvInstance
                     );
    ASSERT_EFI_ERROR (Status);

    //
    // See if it has the ACPI storage file
    //
    Status = FvInstance->ReadFile (
                           FvInstance,
                           (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
                           NULL,
                           &Size,
                           &FileType,
                           &Attributes,
                           &FvStatus
                           );

    //
    // If we found it, then we are done
    //
    if (Status == EFI_SUCCESS) {
      *Instance = FvInstance;
      break;
    }
  }

  //
  // Our exit status is determined by the success of the previous operations
  // If the protocol was found, Instance already points to it.
  //

  //
  // Free any allocated buffers
  //
  gBS->FreePool (HandleBuffer);

  return Status;
}

/**
  This function calculates and updates an UINT8 checksum.

  @param  Buffer          Pointer to buffer to checksum
  @param  Size            Number of bytes to checksum

**/
STATIC
VOID
AcpiPlatformChecksum (
  IN UINT8      *Buffer,
  IN UINTN      Size
  )
{
  UINTN ChecksumOffset;

  ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);

  //
  // Set checksum to 0 first
  //
  Buffer[ChecksumOffset] = 0;

  //
  // Update checksum value
  //
  Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
}

/**
  Entrypoint of Acpi Platform driver.

  @param  ImageHandle
  @param  SystemTable

  @return EFI_SUCCESS
  @return EFI_LOAD_ERROR
  @return EFI_OUT_OF_RESOURCES

**/
EFI_STATUS
EFIAPI
AcpiPlatformEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS                     Status;
  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
  EFI_FIRMWARE_VOLUME2_PROTOCOL  *FwVol;
  INTN                           Instance;
  EFI_ACPI_COMMON_HEADER         *CurrentTable;
  UINTN                          TableHandle;
  UINT32                         FvStatus;
  UINTN                          TableSize;
  UINTN                          Size;

  Instance     = 0;
  CurrentTable = NULL;
  TableHandle  = 0;

  //
  // Find the AcpiTable protocol
  //
  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }

  //
  // Locate the firmware volume protocol
  //
  Status = LocateFvInstanceWithTables (&FwVol);
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // Read tables from the storage file.
  //
  while (Status == EFI_SUCCESS) {

    Status = FwVol->ReadSection (
                      FwVol,
                      (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
                      EFI_SECTION_RAW,
                      Instance,
                      (VOID**) &CurrentTable,
                      &Size,
                      &FvStatus
                      );
    if (!EFI_ERROR(Status)) {
	  //
      //Update specfic Acpi Table
      //If the Table is updated failed, doesn't install it,
      //go to find next section.
      //
      UpdateAcpiTable(CurrentTable);

      //
      // Add the table
      //
      TableHandle = 0;

      TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
      ASSERT (Size >= TableSize);

      //
      // Checksum ACPI table
      //
      AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize);

      //
      // Install ACPI table
      //
      Status = AcpiTable->InstallAcpiTable (
                            AcpiTable,
                            CurrentTable,
                            TableSize,
                            &TableHandle
                            );

      //
      // Free memory allocated by ReadSection
      //
      gBS->FreePool (CurrentTable);

      if (EFI_ERROR(Status)) {
        return EFI_ABORTED;
      }

      //
      // Increment the instance
      //
      Instance++;
      CurrentTable = NULL;
    }
  }

  return EFI_SUCCESS;
}

